package org.coco.mybatis.mapping;

import lombok.Data;
import org.coco.mybatis.binding.MethodSignature;
import org.coco.mybatis.sql.SqlSource;
import org.coco.util.ValidationUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用来解析生成完整sql语句的类
 */
@Data
public class BoundSql {

    private String sql;
    private List<MethodSignature> params;
    //sql查询返回的对象
    private Class<?> clazz;
    private ResultMap resultMap;


    public BoundSql(){}

    public BoundSql parseSqlBySqlSource(SqlSource sqlSource, List<MethodSignature> methodSignatures) {
        String sql = sqlSource.getSqlContent().trim();
        //将sql中所有的${}替换成参数值
        String sqlFirstContent = parse$(sql,methodSignatures);
        //将所有的#{}替换成 ？
        BoundSql boundSql = doParse(sqlFirstContent,methodSignatures);
        return boundSql;
    }

    private BoundSql doParse(String sql, List<MethodSignature> methodSignatures) {
        List<MethodSignature> objs = new ArrayList<>();
        List<Object> listData = parsePre(sql,methodSignatures);
        Object obj = null;
        for(int i = 0; i < listData.size(); i ++) {
            obj = listData.get(i);
            sql = sql.replace("#{"+obj+"}","?");
            boolean flag = true;
            for(int t = 0; t < methodSignatures.size() && flag; t ++) {
                if(methodSignatures.get(t).getName().equals(obj)) {
                    objs.add(methodSignatures.get(t));
                    flag = false;
                    continue;
                }
            }
        }
        BoundSql boundSql = new BoundSql();
        boundSql.setSql(sql);
        boundSql.setParams(objs);
        return boundSql;
    }

    // select * from people where id = #{id} and name = #{name}
    private  List<Object> parsePre(String sql, List<MethodSignature> methodSignatures) {
        List<Object> lists = new ArrayList<>();
        if(sql.contains("#{")) {
            char[] chars = sql.toCharArray();
            int m = 0;
            int n = 0;
            for(int i = 0; i < chars.length; i ++) {
                if("#".equals(String.valueOf(chars[i]))) {
                    m = i;
                    continue;
                }else if("}".equals(String.valueOf(chars[i]))) {
                    n = i;
                }
                if((n-m) > 0 && m > 0 && n > 0 ) {
                    String value = null;
                    if((n + 1) == chars.length) {
                        value = sql.substring(m+1);
                    }else {
                        value = sql.substring(m+1,n+1);
                    }
                    String result = value.substring(1,value.length()-1);
                    Object paramValue = null;
                    if(ValidationUtil.isEmpty(methodSignatures)) {
                        System.err.println("param "+ result + " not exist");
                        throw new RuntimeException("param "+ result + " not exist");
                    }else {
                        boolean paramExist = false;
                        for(int t = 0; t < methodSignatures.size(); t++) {
                            MethodSignature methodSignature = methodSignatures.get(t);
                            String name = methodSignature.getName();
                            if(result.equals(name)) {
                                Class<?> clazz = methodSignature.getClazz();
                                paramValue = methodSignature.getValue();
                                System.out.println(paramValue);
                                paramExist = true;
                            }
                        }
                        if(!paramExist) {
                            System.err.println("param "+ result + " not exist");
                            throw new RuntimeException("param "+ result + " not exist");
                        }
                        lists.add(result);
                    }
                    m = 0;
                    n = 0;
                }
            }

        }else {
            return lists;
        }
        return lists;
    }


    // select * from people where id = ${id} and name = #{name}
    private String parse$(String sql,List<MethodSignature> methodSignatures) {
        if(sql.contains("${")) {
            char[] chars = sql.toCharArray();
            int m = 0;
            int n = 0;
            for(int i = 0; i < chars.length; i ++) {
                if("$".equals(String.valueOf(chars[i]))) {
                    m = i;
                    continue;
                }else if("}".equals(String.valueOf(chars[i]))) {
                    n = i;
                }
                if((n-m) > 0 && m > 0 && n > 0 ) {
                    String value = null;
                    if((n + 1) == chars.length) {
                        value = sql.substring(m+1);
                    }else {
                        value = sql.substring(m+1,n+1);
                    }
                    String result = value.substring(1,value.length()-1);
                    String paramValue = null;
                    if(ValidationUtil.isEmpty(methodSignatures)) {
                        System.err.println("param "+ result + " not exist");
                        throw new RuntimeException("param "+ result + " not exist");
                    }else {
                        boolean paramExist = false;
                        for(int t = 0; t < methodSignatures.size(); t++) {
                            MethodSignature methodSignature = methodSignatures.get(t);
                            String name = methodSignature.getName();
                            if(result.equals(name)) {
                                paramValue = (String) methodSignature.getValue();
                                paramExist = true;
                            }
                        }
                        if(!paramExist) {
                            System.err.println("param "+ result + " not exist");
                            throw new RuntimeException("param "+ result + " not exist");
                        }
                        sql = sql.replace("${"+result+"}",paramValue);
                    }
                    m = 0;
                    n = 0;
                    break;
                }
            }
        }else {
            return sql;
        }
        return parse$(sql,methodSignatures);
    }
}
